package com.test2.opencv;

import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfPoint;
import org.opencv.core.Point;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.highgui.HighGui;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import javax.imageio.ImageIO;
import java.awt.AWTException;
import java.awt.Dimension;
import java.awt.MouseInfo;
import java.awt.Rectangle;
import java.awt.Robot;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;

public class TestOpencv5 {

   private double nndrRatio = 0.8D;

    public static void main(String[] args) throws IOException, AWTException {
        nu.pattern.OpenCV.loadShared();
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);

        new TestOpencv5().getAllRectangualObj(Paths.get("D:\\123.jpg"),10,10,0,0,100);
    }

    public List<Rect> getAllRectangualObj(Path imagePath, int sizeW, int sizeH, int thresholdStrength, int thresholdWeakness, int boundFilter) throws AWTException, IOException {
        long start = System.currentTimeMillis();
        //opencv环境检查
        environmentalInspection();
        Robot robot=new Robot();
        Toolkit toolkit= Toolkit.getDefaultToolkit();
        Dimension d = toolkit.getScreenSize();
        Rectangle screenRect = new Rectangle(d);

        BufferedImage bufferedImage =  robot.createScreenCapture(screenRect);
        ImageIO.write(bufferedImage,"jpg",new File("d:\\test2.jpg"));
        Mat imread = Imgcodecs.imread("d:\\test2.jpg");
        //Mat imread =  Mat2BufImg.BufImg2Mat(bufferedImage,BufferedImage.TYPE_3BYTE_BGR, CvType.CV_8UC3);
        //图片预处理
        Mat desc = imagePreprocessing(imread,sizeW,sizeH);
        HighGui.imshow("预处理", desc);
        //检测边缘
        Mat temp = new Mat();//边缘检测结果
        Imgproc.Canny(desc, temp,thresholdStrength,thresholdWeakness);
        List<MatOfPoint> list = new ArrayList<>();
        Mat hierarchy = new Mat();
        //查找边缘
        Imgproc.findContours(temp, list,hierarchy,Imgproc.RETR_EXTERNAL, Imgproc.CHAIN_APPROX_SIMPLE);//查找边缘为封闭的矩形
        /*
            遍历找到的矩形边缘，当边缘大小超过一定值的时候，记录找到边缘的坐标和宽高
         */
        List<Rect> rects = new ArrayList<>();
        for (int i = 0; i < list.size(); i++) {//遍历查找到的边缘
            MatOfPoint mp = list.get(i);
            double v = Imgproc.contourArea(mp);//获取边缘大小
            if(v > boundFilter ) {
                Rect rect = Imgproc.boundingRect(mp);//边缘转化为矩形
                    rects.add(rect);
            }
        }
        //展示
        HighGui.imshow("原图", imread);
        HighGui.imshow("处理后", desc);
        Mat out = new Mat(imread.size(),imread.type());
        imread.copyTo(out);
        rects.forEach(rect->{
            Imgproc.rectangle(out, rect, new Scalar(0,0,255));
        });
        HighGui.imshow("边缘检测", out);
        System.out.println("use time:"+(System.currentTimeMillis() - start));
        HighGui.waitKey(0);

        return rects;
    }
    /**
     * 图片预处理
     * @param imread 图片对象
     * @param sizeW 像素点加粗宽度
     * @param sizeH 像素点加粗高度
     * @return 处理后的对象
     */
    private Mat imagePreprocessing(Mat imread,int sizeW,int sizeH) {
        Mat desc = new Mat();
        //转为灰度
        Imgproc.cvtColor(imread, desc, Imgproc.COLOR_BGR2GRAY);
        //图像反向二值化,去除噪点
        Imgproc.threshold(desc,desc, 187, 255, Imgproc.THRESH_BINARY_INV|Imgproc.THRESH_OTSU);
        //像素点加粗到sizeW*sizeH，让矩形闭合
        Mat element = Imgproc.getStructuringElement(Imgproc.MORPH_RECT, new Size(sizeW,sizeH));
        Imgproc.morphologyEx(desc, desc, Imgproc.MORPH_GRADIENT, element);
        //去除边框的线条干扰
        int cutNum = 23;
        Mat submat = desc.submat(cutNum,desc.rows()-cutNum,cutNum,desc.cols()-cutNum);
        //写入临时文件，读取后再删除，避免直接添加边框图片内容又恢复的问题
        Imgcodecs.imwrite("temp.jpg", submat);
        Mat temp = Imgcodecs.imread("temp.jpg");
        try {
            Files.delete(Paths.get("temp.jpg"));
        } catch (IOException e) {
            e.printStackTrace();
        }
        //减去的边缘再填充回来，避免生成的坐标变位
        Core.copyMakeBorder(temp, temp, cutNum, cutNum, cutNum, cutNum, Core.BORDER_CONSTANT,new Scalar(0,0,0));
        return temp;
    }

    /**
     * opencv 环境检查
     */
    private void environmentalInspection() {
        System.loadLibrary(Core.NATIVE_LIBRARY_NAME);
        System.out.println("opencv = " + Core.VERSION);
    }


}
